/*
 * @Author: liqing
 * @Date: 2022-03-29 11:17:08
 * @LastEditors: liqing
 * @LastEditTime: 2023-06-08 10:21:12
 * @Description: description
 */
'use strict'

var localVideo = document.getElementById('local_video');

var startButton = document.getElementById('startButton');
var callButton = document.getElementById('callButton');
var hangupButton = document.getElementById('hangupButton');

var pc;
var localStream;
var socket = io.connect();

var config = {
  'iceServers': [{
    'urls': 'stun:stun.l.google.com:19302'
  }]
};

const offerOptions = {
  offerToReceiveVideo: 1,
  offerToReceiveAudio: 1
};


callButton.disabled = false;
hangupButton.disabled = true;

startButton.addEventListener('click', startAction);
callButton.addEventListener('click', callAction);
hangupButton.addEventListener('click', hangupAction);

function gotDevices(infos) {
  // document.getElementById("data").innerHTML = JSON.stringify(infos);
}

function startAction() {
  try {
    // 测试获取设备后置摄像头
    navigator.mediaDevices.enumerateDevices().then(gotDevices);
    // 关于navigator.mediaDevices.getUserMedia的定义可以参考https://developer.mozilla.org/zh-CN/docs/Web/API/MediaDevices/getUserMedia
    navigator.mediaDevices.getDisplayMedia({video: true, audio: false})
      .then(function (mediastream) {
        // 把音视频流放入变量localStream以及localVideo这个dom中
        localStream = mediastream;
        localVideo.srcObject = mediastream;
        startButton.disabled = true;
      }).catch(function (e) {
      // 如果获取本地音视频时无外接设备（摄像头/麦克风）则会提示exception is NotFoundError: Requested device not found
      console.log(`exception is ${e}`);
      alert(`exception is ${e}`);
    });
  } catch (e) {
    alert(`startAction exception is ${e}`);
  }
}

function callAction() {
  callButton.disabled = true;
  hangupButton.disabled = false;
  // pc = new RTCPeerConnection(config);
  // 创建一个本地到远端的webRTC对象
  pc = new RTCPeerConnection();
  // 获取媒体流中的轨道信息
  let tracks = localStream.getTracks();
  // 向上面生成的webRTC对象注入轨道信息
  tracks.forEach(track => pc.addTrack(track, localStream));
  // 作为源端创建offer对象（包含源端的媒体信息和编解码信息）
  pc.createOffer(offerOptions).then(function (offer) {
    // 在webRTC对象中记录offer信息（注意记录本端信息调用的是setLocalDescription，记录对端信息调用的是setRemoteDescription）
    console.log(`offer is ${JSON.stringify(offer)}`);
    pc.setLocalDescription(offer);
    // 同步offer信息给目的端（offer对象中的SDP参数含义可以参考https://blog.csdn.net/m370809968/article/details/88195181,SDP即为信令）
    socket.emit('signal', offer);
  });
  // 当webRTC对象调用setLocalDescription方法时会抛出icecandidate事件（即触发以下监听的回调）
  // 问题：为什么调用setLocalDescription方法会抛出icecandidate事件两次（两次信息不完全相同，如端口）
  pc.addEventListener('icecandidate', function (event) {
    var iceCandidate = event.candidate;
    console.log(`iceCandidate is ${JSON.stringify(iceCandidate)}`);
    if (iceCandidate) {
      // 同步补充描述信息给目的端（通过SDP协商结果进行信息交换），描述信息包括协议、IP、端口、优先级等等信息
      // 问题：为什么这些描述信息不可以放在信令中
      socket.emit('ice', iceCandidate);
    }
  });
  // 当信令和补充信息双方同步完成后即可开始会商
}

function hangupAction() {
  localStream.getTracks().forEach(track => track.stop());
  pc.close();
  pc = null;
  hangupButton.disabled = true;
  callButton.disabled = true;
  startButton.disabled = false;
}

socket.on('create', function (room, id) {
  console.log('userA创建聊天房间');
  console.log(room + id);
});

socket.on('call', function () {
  console.log('enter call');
  callButton.disabled = false;
});

// 监听目的端同步的offer信息
socket.on('signal', function (message) {
  if (pc !== 'undefined') {
    // 在webRTC对象中记录目的端offer信息（注意记录本端信息调用的是setLocalDescription，记录对端信息调用的是setRemoteDescription）
    pc.setRemoteDescription(new RTCSessionDescription(message));
    setTimeout(function () {
      console.log(`remote answer is ${JSON.stringify(pc.remoteDescription)}`);
    }, 1000);
  }
});

socket.on('ice', function (message) {
  if (pc !== 'undefined') {
    pc.addIceCandidate(new RTCIceCandidate(message));
    console.log('become candidate');
  }
});

socket.emit('create or join', 'room');

